﻿package artibella.media.video
{

	import artibella.IDisposable;
	import artibella.ILoaderAgent;
	import artibella.loaders.video.NetStreamClient;
	
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.NetStatusEvent;
	import flash.media.Video;
	import flash.net.NetConnection;
	import flash.net.NetStream;
	import flash.net.ObjectEncoding;
	

	/**
	 * ...
	 * @author pbordachar
	 */
	
	public class MoviePlug extends EventDispatcher implements IDisposable
	{
		public static const PLAY_START:String = "play_start";
		public static const PLAY_STOP:String = "play_stop";
		public static const BUFFER_FULL:String = "buffer_full";
		
		private var _nc:NetConnection;
		private var _ns:NetStream;

		private var _video:Video;
		private var _flux:String;
		private var _server:String;
		
		private var _duree:Number;
		private var _buffer:int = 2;
		private var _paused:Boolean = false;
		private var _loop:Boolean = false;
		private var _function:Function;
		private var _agent:ILoaderAgent;
		
		private var _flushed:Boolean = false; //

		public function MoviePlug( video:Video, flux:String, parameters:MoviePlugParameters = null )
		{
			_video = video;
			_flux = flux;
			
			if( parameters != null ){
				_server = parameters.server;
				_buffer = parameters.buffered;
				_paused = parameters.paused;
				_loop = parameters.looped;
				_function = parameters.onComplete;
				_agent = parameters.agent;
			}
			
			//_init();
		}
		
		//private function _init():void
		//{
			//_connect();
		//}
		
		public function connect():void
		{
			_connect();
		}
		
		///////   N E T   C O N N E C T I O N
		
		private function _connect():void
		{
			NetConnection.defaultObjectEncoding = ObjectEncoding.AMF0;
			
			_nc = new NetConnection();
			_nc.client = this;
			_nc.objectEncoding = ObjectEncoding.AMF0;
			_nc.addEventListener( NetStatusEvent.NET_STATUS, onNCStatus );
			_nc.connect( _server );
		}

		public function onNCStatus( e:NetStatusEvent ):void
		{
			switch( e.info.code ) {
				
				case "NetConnection.Call.BadVersion" :
				case "NetConnection.Call.Failed" :
				case "NetConnection.Call.Prohibited" :
				case "NetConnection.Connect.AppShutdown" :
				case "NetConnection.Connect.InvalidApp" :
				case "NetConnection.Connect.Closed" :
				case "NetConnection.Connect.Failed" :
				case "NetConnection.Connect.Rejected" :
					break;
					
				case "NetConnection.Connect.Success" :
					start();
					break;
					
				default :
					trace( e.info.code );
			}
			
			_nc.removeEventListener( NetStatusEvent.NET_STATUS, onNCStatus );
		}
		
		///////   N E T   S T R E A M
		
		public function start( url:String = null ):void
		{
			if ( _nc == null ) return;
			
			if( url != null ){
				_flux = url;
			}
			
			_ns = new NetStream( _nc );
			_ns.checkPolicyFile = false;
			_ns.bufferTime = _buffer;
			
			_ns.client = new NetStreamClient();
			_ns.addEventListener( NetStatusEvent.NET_STATUS, onNSStatus );
			
			_video.attachNetStream( _ns );
			
			_play();
			
		}
		
		private function _play():void
		{
			if( _paused ){
				
				_ns.play( _flux );
				_ns.pause();
				
			} else {
				
				_ns.play( _flux );
			}
		}
		
		// - - -
		
		public function doPlay():void
		{
			_paused = false;
			if ( _ns ) {
				_play();
			} else {
				_connect(); // just in case connect() is forgotten
			}
		}
		
		//public function doPause():void
		//{
			//_paused = true;
			//if( _ns ) _play();
		//}
		
		public function doPause( b:Boolean ):void
		{
			_paused = b;
			if( _ns ) {
				if( _paused ) {
					_ns.pause();
				} else {
					_ns.resume();
				}
			}
		}
		
		public function doStop():void
		{
			_paused = true;
			if ( _ns ) {
				_ns.seek( 0 )
				_play();
			}
		}
		
		// ---
		
		public function onNSStatus( e:NetStatusEvent ):void
		{ 
			//trace( e.info.code );
			
			switch( e.info.code ) {
				
				case "NetStream.Play.Start" :
					dispatchEvent( new Event( PLAY_START ) );
					if( _agent ) _agent.addIndicator();
					break;
					
				case "NetStream.Play.Stop" :
					dispatchEvent( new Event( PLAY_STOP ) );
					if ( _agent ) _agent.removeIndicator();
					_checkComplete(); 
					break;
					
				/// B U F F E R 
					
				case "NetStream.Buffer.Empty" :
					if( !_paused ){
						if( _agent ) _agent.addIndicator();
					} else {
						if( _agent ) _agent.removeIndicator();
					}
					break;

				case "NetStream.Buffer.Full" :
					_flushed = false; 
					dispatchEvent( new Event( BUFFER_FULL ) );
					if( _agent ) _agent.removeIndicator();
					break;
				
				case "NetStream.Buffer.Flush" :
					_flushed = true;
					_checkComplete();
					break;
					
				/// S E E K	
				
				case "NetStream.Seek.Failed" :
				case "NetStream.Seek.Notify" :
					break;
				
				default :
				
					if( e.info.level == "error" ){
						trace("Stream Not Found");
					}
			}
		}
		
		private function _checkComplete():void
		{
			if( _flushed && _ns.client.duree > 0 && ( _ns.client.duree - _ns.time) < .1 ) {
				if ( !_loop ) {
					_paused = true;
					if ( _function != null ) _function();
					return;
				}

				_ns.seek( 0 );
				_play();
			}
		}
		
		private function _closeStream():void
		{
			if ( _ns != null ) {
				_ns.removeEventListener( NetStatusEvent.NET_STATUS, onNSStatus );
				_ns.pause();
				_ns.close();
			}
			if( _nc != null ){
				_nc.close();
			}
		}
		
		//----- IDisposable
		
		public function dispose():void
		{
			_closeStream();
			
			_ns = null;
			_nc = null;
			
			_video = null;
			_agent = null;
			_function = null;
		}		
	}
}